/***************************************************************
*
* (c) 2008 Markus Dittrich 
*
* This program is free software; you can redistribute it 
* and/or modify it under the terms of the GNU General Public 
* License Version 3 as published by the Free Software Foundation. 
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License Version 3 for more details.
*
* You should have received a copy of the GNU General Public 
* License along with this program; if not, write to the Free 
* Software Foundation, Inc., 59 Temple Place - Suite 330, 
* Boston, MA 02111-1307, USA.
*
****************************************************************/

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

/* STL includes */
#include <list>
#include <map>
#include <string>
#include <vector>

/* boost includes */
#include <boost/utility.hpp>

/* QT includes */
#include <QList>
#include <QMainWindow>
#include <QMutex>
#include <QString>

/* local includes */
#include "data_label_manager.h"
#include "data_object.h"
#include "io.h"
#include "plot_properties.h"
#include "settings.h"
#include "utilities.h"

/* a few forward declarations */
class DataSelectorWidget;
class QAction;
class QColor;
class QEvent;
class QFrame;
class QGridLayout;
class QGroupBox;
class QLabel;
class QListWidgetItem;
class QMenuBar;
class QMenu;
class QPainter;
class QProgressBar;
class QRadioButton;
class QSplitter;
class QStackedWidget;
class QStatusBar;
class QTabWidget;
class QVBoxLayout;

class GraphCanvas;
class BasePropertyWidget;


/* convenience typedefs */
typedef std::pair<QString, DataObjectPtr> DataContainerItem;
typedef std::pair<QString, PlotPropertiesPtr> PlotPropertiesItem;
typedef std::map<QString, DataObjectPtr> DataMap;
typedef std::map<QString, PlotPropertiesPtr> PlotPropertiesMap;
typedef std::map<QString,DataObjectPtr>::const_iterator dataMapIterator;

/* use anonymous namespace to define some constants */
namespace {
  const QString NAME = "dvalin";
  const QString VERSION = "0.1";
  const QString IDENTIFIER = NAME + "-" + VERSION;
  const int SPLITTER_MIN_HEIGHT = 580;
  const int SPLITTER_MIN_WIDTH = 1000;
  const int CANVAS_MIN_HEIGHT = SPLITTER_MIN_HEIGHT;
  const int CANVAS_MIN_WIDTH = 750;
  const int TAB_WIDGET_MIN_HEIGHT = SPLITTER_MIN_HEIGHT - 100;
  const int TAB_WIDGET_MIN_WIDTH = 270; 
}

/***************************************************************
 * 
 * The MainWindow class organizes the layout of itchy's main
 * window
 *
 ***************************************************************/
class MainWindow 
  : 
    public QMainWindow,
    public boost::noncopyable
{
  
  Q_OBJECT

    
public:

  explicit MainWindow(const std::vector<QString>& fileNames);


signals:

  void graph_color_changed(const QString&, const QColor&);


public slots:

  void redraw_and_rescale_canvas();
  void redraw_canvas();
  void reload_data_();
  void show_histogram_selector();
  void list_in_status_bar(QString fileName);
  void signal_file_reading_error(QString fineName);
  void hide_data_items(bool state, QList<QString>);
  void delete_data_items(QList<QString>);
  void generate_histogram(int numBins, bool normalize);
  void update_histogram(const QString& dataName, 
      const QString& histogramName, int numBins, bool normalize);

  
private slots:
  
  void add_data_to_gui_();
  void exit_dvalin_();
  void start_progress_bar_();
  void stop_progress_bar_();
  void show_info_();
  void show_about_qt_info_();
  void show_export_canvas_widget_();
  void show_open_new_file_widget_();
  void show_label_widget_();
  void show_print_canvas_widget_();
  void show_settings_widget_();
  void toggle_data_visibility_(bool state);
  void update_mouse_position(double xPos, double yPos);
 

private:

  /* interface generation functions */
  void create_menu_bar_();
  void populate_menu_bar_();
  void create_tool_bar_();
  void create_file_menu_();
  void create_look_and_feel_menu_();
  void create_transformations_menu_();
  void create_help_menu_();
  void create_status_bar_();
  
  void create_main_splitter_();
  void create_data_selector_widget_();
  void create_data_property_widget_();
  void create_canvas_();
  void add_widgets_to_splitter_();

  /* general helper functions */
  void generate_ioHandler_();
  PlotPropertiesPtr initialize_plot_properties_(QString aName);
  void add_data_property_tab_(QString dataName, DataObjectPtr theData,
      PlotPropertiesPtr properties);
  void add_histogram_(const QString& dataName, 
      DataObjectPtr histogramData, int numBins, bool normalize);
  void add_histogram_property_tab_(const QString& dataName,
      const QString& histogramName, DataObjectPtr theData, 
      PlotPropertiesPtr properties, int numBins, bool normalize);
  void update_individual_property_tab_(const QString& name);

  void add_to_active_data_(QString name);
  void remove_from_active_data_(QString name);

  void add_to_data_label_manager_(QString name);
  void remove_from_data_label_manager_(QString name);

  void add_to_data_selector_(QString name);

  QWidget* get_active_data_widget_();
  QString get_active_data_name_();
  const QColor& get_graph_color_(QString name);
  BasePropertyWidget* get_data_property_widget_(const QString& name);

  /* widget data members */
  QSplitter* mainSplitter_;
  QGroupBox* dataSelectorGrouper_;
  DataSelectorWidget* dataSelector_;
  QStackedWidget* dataControl_; 
  QStatusBar* statusBar_;

  /* status bar stuff */
  QProgressBar* fileLoadProgressBar_;
  QLabel* statusBarMessages_;
  QLabel* currentCoordinateWidget_;

  /* menu bar stuff */
  QMenuBar* menuBar_;

  /* mutex for synchronizing threads */
  QMutex mutex_;

  /* canvas on which the actual data is being displayed */
  GraphCanvas* canvas_;

  /* IO class handles reading of data */
  IO* ioHandler_;
  
  /* data members 
   * NOTE: activeData_ is used to keep track of all
   * active and completely initialized data sets. Since IO is
   * done asynchronously in a separate thread, dataContainer_
   * can not be used for this purpose since it may already 
   * contain new data while others (such as plot properties) 
   * have not yet been updated. 
   */
  std::vector<QString> activeData_;
  DataMap dataContainer_;
  PlotPropertiesMap plotPropertiesContainer_;
  DataLabelManager dataLabels_;
  Settings settings_;
 
  /* ids used to number consecutive instances of data sets */
  int histogramCounter_;
};


#endif
